package com.spring.dynamicdatasource.service.impl;

import com.spring.dynamicdatasource.config.DynamicDataSource;
import com.spring.dynamicdatasource.dto.ConnectionDTO;
import com.spring.dynamicdatasource.service.DataSourceService;
import com.spring.dynamicdatasource.utils.Keys;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID;

/**
 * 数据源管理
 *
 * @author HouKunLin
 * @date 2019/9/10 0010 11:50
 */
@Service
public class DataSourceServiceImpl implements DataSourceService {

    @Autowired
    private DynamicDataSource dynamicDataSource;

    @Autowired
    private Configuration configuration;

    @Autowired
    private HttpSession session;

    @Override
    public DataSource registerDateSource(ConnectionDTO dto) throws Exception {
        try {
            // 构建新数据源
            DataSource dataSource = DataSourceBuilder.create()
                    .url(getJdbcUrl(dto))
                    .username(dto.getUsername())
                    .password(dto.getPassword())
                    .type(com.zaxxer.hikari.HikariDataSource.class)
                    .build();
            checkDataSource(dataSource);
            // 重设并通知，维护的TargetDataSource
            registerDateSource(dataSource);
            return dataSource;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    @Override
    public DataSource registerDateSource(DataSource dataSource) {
        removeDataSource(session);

        String key = UUID.randomUUID().toString();

        session.setAttribute(Keys.datasourcesKey, key);
        session.setAttribute(Keys.datasources, dataSource);

        dynamicDataSource.put(key, dataSource);
        return dataSource;
    }

    @Override
    public void removeDataSource(DataSource dataSource) {
        dynamicDataSource.remove(dataSource);
    }

    @Override
    public void removeDataSource(String key) {
        dynamicDataSource.remove(key);
    }

    @Override
    public void removeDataSource(HttpSession session) {
        String key = String.valueOf(session.getAttribute(Keys.datasourcesKey));

        session.removeAttribute(Keys.datasourcesKey);
        session.removeAttribute(Keys.datasources);

        removeDataSource(key);
    }

    /**
     * 检查一个数据源是否能够正常连接数据库
     *
     * @param dataSource
     * @throws Exception
     */
    private void checkDataSource(DataSource dataSource) throws Exception {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public String getJdbcUrl(ConnectionDTO dto) throws Exception {
        Template template = configuration.getTemplate(dto.getType().getKey(), "UTF-8");
        return FreeMarkerTemplateUtils.processTemplateIntoString(template, dto);
    }
}
